﻿#include "discrete_face_plane.hxx"
#include "idx_mesh_utils.hxx"
#include "discrete_face_loop.hxx"
#include <array>
#include <vector>

/**
 * @brief 将给定的平面使用约束的Delaunay三角剖分（CDT）离散成三角形网格
 *
 * @param f 一个指针指向要离散的平面对象
 * @param nt 法向容差
 * @param st 距离容差
 * @return 一个表示操作成功或失败的outcome对象
 */
outcome facet_face_plane(FACE* f, double nt, double st) {
    // points变量用于存放边离散后的点
    // 格式为((u1,v1),(u2,v2),...)
    std::vector<CDT::V2d<double>> points;

    // edges变量用于存放连接点的边
    // 格式为((e1,e2),(e2,e3),...)
    // 其中(ei,ej)的ei为首顶点下标,ej为尾顶点下标
    std::vector<CDT::Edge> edges;
    LoopProcessor loop_processor(f);
    loop_processor.Execute();
    for (auto x : loop_processor.points) {
        points.emplace_back(x.u, x.v);
    }
    for (int loop_idx = 0; loop_idx < loop_processor.loops_indexs.size(); loop_idx++) {
        auto& point_indexs = loop_processor.loops_indexs[loop_idx];
        int point_indexs_size = point_indexs.size();
        if (point_indexs_size < 2) continue;
        for (int i = 1; i < point_indexs_size; i++) {
            edges.emplace_back(point_indexs[i], point_indexs[i - 1]);
        }
        edges.emplace_back(point_indexs.front(), point_indexs.back());
    }
    CDT::Triangulation<double> cdt;

    // 去除重复点, 重映射边
    CDT::RemoveDuplicatesAndRemapEdges(points, edges);

    // 插入点和边
    cdt.insertVertices(points);
    cdt.insertEdges(edges);

    // 使用带限制的CDT函数进行离散
    cdt.eraseOuterTrianglesAndHoles();
    // 更新points为三角剖分后的顶点集
    points = cdt.vertices;

    // 将points变量中的点加入mesh中
    // 需要判断点的法向和面的法向是否相同。若不同，需要对点的方向取逆向后加入
    // 遍历所有点
    std::vector<UV_VERTEX> uv_vertices;
    for (int i = 0; i < points.size(); i++) {
        // 参数空间中点的位置
        SPApar_pos par_pos(points[i].x, points[i].y);
        // 将参数位置转换为3D位置
        SPAposition pos = f->geometry()->equation().eval_position(par_pos);
        SPAunit_vector normal = f->geometry()->equation().eval_normal(par_pos);
        if (f->sense()) {
            normal = -normal;
        }
        uv_vertices.emplace_back(pos, normal, par_pos);
    }
    NewIndexedMesh(f, uv_vertices, cdt.triangles);
    return outcome();
}
